﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;

namespace ThingyCloudWPF.Creatures.Properties
{
	public class PropertiesManager
	{
		/// <summary>
		/// The only instance of this class
		/// </summary>
		private static PropertiesManager instance = null;

		/// <summary>
		/// A list of all properties for thingies
		/// </summary>
		private List<ThingyProperties> ThingyProperties;

		/// <summary>
		/// A list of all properties for thingies
		/// </summary>
		private List<AvatarProperties> AvatarProperties;

		/// <summary>
		/// Private constructor to ensure singleton
		/// </summary>
		private PropertiesManager()
		{
			// Prepare collections
			ThingyProperties = new List<ThingyProperties>();
			AvatarProperties = new List<AvatarProperties>();

			Read();
		}

		/// <summary>
		/// Returns the only available instance of this class
		/// </summary>
		public static PropertiesManager Instance
		{
			get
			{
				if (instance == null)
					instance = new PropertiesManager();

				return instance;
			}
		}

		/// <summary>
		/// Returns new, random thingy properties
		/// </summary>
		/// <returns></returns>
		public ThingyProperties GetRandomThingyProperties()
		{
			Random random = new Random((int)DateTime.Now.Ticks);
			return ThingyProperties[random.Next(0, ThingyProperties.Count)];
		}

		/// <summary>
		/// Gets random avatar properties with the desired weight
		/// </summary>
		public CreatureProperties GetAvatarProperties(int weight)
		{
			// First select all avatars that 
			var candidates1 = from ap in AvatarProperties
							  where ap.Weight <= weight
							  orderby ap.Weight descending
							  select ap;

			// This is the weight we'll be using
			int selectWeight = candidates1.First().Weight;

			// Now select all with that weight
			var properties = from p in candidates1
							 where p.Weight == selectWeight
							 select p;

			Random random = new Random((int)DateTime.Now.Ticks);
			return properties.ElementAt(random.Next(0, properties.Count()));
		}

		/// <summary>
		///  Reads the XML file and places al the Properties in Hashtables
		/// </summary>
		private void Read()
		{
			// Read creature settings
			XmlDocument doc = new XmlDocument();
			doc.Load("CreatureSettings.xml");

			// All creatures are under the root node
			XmlNodeList creatures = doc.DocumentElement.ChildNodes;

			// Process all creatures
			foreach (XmlNode node in creatures)
			{
				// Skip comments
				if (node.NodeType == XmlNodeType.Comment)
					continue;

				// The creature type should be in an attribute 'type'
				string type = node.Attributes.GetNamedItem("type").InnerText;

				// Always has an id which can be cast to an integer
				int id = int.Parse(node.SelectNodes("id")[0].InnerText);

				// Both thingies and avatars have variants
				List<Variant> variants = new List<Variant>();
				XmlNodeList variantNodes = node.SelectNodes("variants/variant");
				foreach (XmlNode variant in variantNodes)
				{
					// Read the ID and animation
					int variantId = int.Parse(variant.InnerText);
					string animation = variant.Attributes.GetNamedItem("animation").InnerText;

					// Create a new variant for this one and add it to the list of variants of the properties
					Variant var = new Variant(variantId, animation);
					variants.Add(var);
				}

				//Debug.WriteLine(string.Format("Found a creature w/ ID {0}", id));

				// Thingies have a speed
				if (type == "thingy")
				{
					// Read and save speed
					int speed = int.Parse(node.SelectNodes("speed")[0].InnerText);

					// Thingy configuration!
					ThingyProperties props = new ThingyProperties(id, speed);
					props.Variants.AddRange(variants);

					// Save!
					ThingyProperties.Add(props);
					Debug.WriteLine(props.ToString());
				}
				// Read avatar properties
				else if (type == "avatar")
				{
					// Read weight
					int weight = int.Parse(node.SelectNodes("weight")[0].InnerText);

					// Create properties
					AvatarProperties props = new AvatarProperties(id, weight);
					props.Variants.AddRange(variants);

					// Save!
					AvatarProperties.Add(props);
					Debug.WriteLine(props.ToString());
				}
			}
		}
	}
}